#include "stdio.h"
#include "cpu.h"
#include "swap_proc.h"

typedef struct proc_t proc;
#define MAX_PROC 4
#define PMIN ((unsigned char)255)
proc proc_array[MAX_PROC];
proc* proc_current;
int pid_current = 0;
extern int sec;

extern void ctx_sw(int* zone_old,int* zone_new);

// ZONE : [EBX, ESI, EDI, ESP, EBP]

void init_structures()
{
	//initialization idle
	proc_array[0].pid = 0; //idle
	proc_array[0].status = 'f';
	proc_array[0].wake_time = -1;
	proc_array[0].priority = 254;
	proc_current = &proc_array[0];
	//creating other process
	cree_processus(proc1, 0);
	cree_processus(proc2, 10);
	cree_processus(proc3, 20);
}

int cree_processus(void (*code)(void), unsigned char priority)
{
	pid_current++;
	if(pid_current > MAX_PROC - 1){
		return -1;
	}
	proc_array[pid_current].pid = pid_current;
	proc_array[pid_current].zone[3] = (int)(proc_array[pid_current].stack +
			SIZE_ST -1);
	proc_array[pid_current].stack[SIZE_ST - 1] = (int) code;
	proc_array[pid_current].status = 'f';
	proc_array[pid_current].wake_time = -1;
	proc_array[pid_current].priority = priority;
	return 0;
}

void sleep(int time){
	proc_current -> status = 't';
	proc_current -> wake_time = sec + time;
	ordonnance();
}

void ordonnance()
{
	int pid_next = 0;
	unsigned char pmax = PMIN;
	for(int i = 0; i < MAX_PROC; i++){
		if((sec >= proc_array[i].wake_time) &&
				(proc_array[i].status == 't')){
			proc_array[i].status = 'f'; // wake up!
		}
		if((proc_array[i].priority < pmax) && (proc_array[i].status == 'f')){
			pid_next = proc_array[i].pid;
			pmax = proc_array[i].priority;
		}
	}
	// process switching
	int* zone_old = proc_current -> zone;
	proc_current = &proc_array[pid_next]; // switch the current proc
	ctx_sw(zone_old, proc_array[pid_next].zone);


	/*
	// no priority
	int pid_next = (mon_pid() + 1) % 4;
	while(proc_array[pid_next].status == 't'){ // is sleeping
		pid_next = (pid_next + 1) % 4;
	}

	if(mon_pid() != pid_next){
		int* zone_old = proc_current -> zone;
		proc_current = &proc_array[pid_next]; // switch the current proc
		ctx_sw(zone_old, proc_array[pid_next].zone);
	}
	*/
}

int mon_pid()
{
	return proc_current -> pid;
}
void idle(void)
{
	for (;;) {
		//printf("[idle] pid = %i\n", mon_pid());
		sti();
		hlt();
		cli();
	}

	/* seance 3
	for (int i = 0; i < 3; i++) {
        printf("idle \n");
        ctx_sw(proc_array[0].zone, proc_array[1].zone);
        printf("idle return\n");
    }
    printf("halting system...");
    hlt();
    */

}

void proc1(void) {
	for (;;) {
		printf("[processus 1] pid = %i\n", mon_pid());
		sti();
		sleep(2);
		cli();
	}

	/*
	// seance 3
	while(1){
		printf("executing proc1...\n");
		printf("going idle...\n");
		ctx_sw(proc_array[1].zone, proc_array[0].zone);
	}
	*/
}

void proc2()
{
	for (;;){
		printf("[processus 2] pid = %i\n", mon_pid());
		sti();
		sleep(3);
		cli();
	}
}

void proc3()
{
	for (;;){
		printf("[processus 3] pid = %i\n", mon_pid());
		sti();
		sleep(5);
		cli();
	}
}
